//
// Created by Amon on 2021/10/16.
//

#include <dlfcn.h>
#include "JNIBridge.h"

JNIBridge::JNIBridge(JavaVM *javaVm, jobject callbackObj, jclass nativeCrashMonitorClazz) {
    this->javaVm = javaVm;
    this->callbackObj = callbackObj;
    this->nativeCrashMonitorClazz = nativeCrashMonitorClazz;
}

void JNIBridge::throwException2Java(struct _native_handler_context *handler_context) {
    JNIEnv *env = nullptr;
    if (this->javaVm->AttachCurrentThread(&env, nullptr) != JNI_OK) {
        LOGE("AttachCurrentThread failed");
    }
    jmethodID getStackInfoByThreadNameMid = env->GetStaticMethodID(this->nativeCrashMonitorClazz,
                                                                   "getStackInfoByThreadName",
                                                                   "(Ljava/lang/String;)V");
    jstring jThreadName = env->NewStringUTF(handler_context->thread_name);
    env->CallStaticVoidMethod(nativeCrashMonitorClazz, getStackInfoByThreadNameMid, jThreadName);
    LOGE("ReleaseStringUTFChars");
    int frame_size = handler_context->frame_size;
    LOGE("frame_size :%d", frame_size);
    for (int i = 0; i < frame_size; ++i) {
        uintptr_t pc = handler_context->frames[i];
        Dl_info dl_info;
        if (dladdr(reinterpret_cast<const void *>(pc), &dl_info) != 0 &&
            dl_info.dli_fname != nullptr) {
            const auto near = (uintptr_t) dl_info.dli_saddr;
            const uintptr_t offs = pc - near;
            const uintptr_t addr_rel = pc - (uintptr_t) dl_info.dli_fbase;
            const uintptr_t addr_to_use = is_dll(dl_info.dli_fname) ? addr_rel : pc;
            LOGD("native crash #%02x pc 0x%016x %s (%s+0x%x)",
                 i, addr_to_use, dl_info.dli_fname, dl_info.dli_sname, offs);
        } else {
            LOGE("error :%d", i);
        }
    }
    this->javaVm->DetachCurrentThread();
    LOGE("DetachCurrentThread");
}
